home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1997 February / EnigmA AMIGA RUN 15 (1997)(G.R. Edizioni)(IT)[!][issue 1997-02][PLANET CD V].iso / enigma / earcd / emula / arosdv19.lha / AROS / exec / allocmem.c < prev    next >
C/C++ Source or Header  |  1996-10-24  |  7KB  |  298 lines

  1. /*
  2.     (C) 1995-96 AROS - The Amiga Replacement OS
  3.     $Id: allocmem.c,v 1.9 1996/10/24 15:50:44 aros Exp $
  4.     $Log: allocmem.c,v $
  5.     Revision 1.9  1996/10/24 15:50:44  aros
  6.     Use the official AROS macros over the __AROS versions.
  7.  
  8.     Revision 1.8  1996/10/19 17:07:24  aros
  9.     Include <aros/machine.h> instead of machine.h
  10.  
  11.     Revision 1.7  1996/09/13 17:51:22  digulla
  12.     Use IPTR
  13.  
  14.     Revision 1.6  1996/08/23 17:06:56  digulla
  15.     Began work on ressource tracking
  16.  
  17.     Revision 1.5  1996/08/16 14:05:12  digulla
  18.     Added debug output
  19.  
  20.     Revision 1.4  1996/08/13 13:55:57  digulla
  21.     Replaced AROS_LA by AROS_LHA
  22.     Replaced some AROS_LH*I by AROS_LH*
  23.     Sorted and added includes
  24.  
  25.     Revision 1.3  1996/08/01 17:41:04  digulla
  26.     Added standard header for all files
  27.  
  28.     Desc:
  29.     Lang:
  30. */
  31. #include <exec/alerts.h>
  32. #include <exec/execbase.h>
  33. #include <aros/asmcall.h>
  34. #include <aros/rt.h>
  35. #include <aros/machine.h>
  36. #include "memory.h"
  37.  
  38. #include "exec_debug.h"
  39. #ifndef DEBUG_AllocMem
  40. #   define DEBUG_AllocMem 0
  41. #endif
  42. #if DEBUG_AllocMem
  43. #   undef DEBUG
  44. #   define DEBUG 1
  45. #endif
  46. #include <aros/debug.h>
  47.  
  48. /*****************************************************************************
  49.  
  50.     NAME */
  51.     #include <exec/memory.h>
  52.     #include <clib/exec_protos.h>
  53.  
  54.     AROS_LH2(APTR, AllocMem,
  55.  
  56. /*  SYNOPSIS */
  57.     AROS_LHA(ULONG, byteSize,     D0),
  58.     AROS_LHA(ULONG, requirements, D1),
  59.  
  60. /* LOCATION */
  61.     struct ExecBase *, SysBase, 33, Exec)
  62.  
  63. /*  FUNCTION
  64.     Allocate some memory from the sytem memory pool with the given
  65.     requirements.
  66.  
  67.     INPUTS
  68.     byteSize     - Number of bytes you want to get
  69.     requirements - Type of memory
  70.  
  71.     RESULT
  72.     A pointer to the number of bytes you wanted or NULL if the memory
  73.     couldn't be allocated
  74.  
  75.     NOTES
  76.     The memory is aligned to sizeof(struct MemChunk). All requests
  77.     are rounded up to a multiple of that size.
  78.  
  79.     EXAMPLE
  80.     mytask=(struct Task *)AllocMem(sizeof(struct Task),MEMF_PUBLIC|MEMF_CLEAR);
  81.  
  82.     BUGS
  83.  
  84.     SEE ALSO
  85.     FreeMem()
  86.  
  87.     INTERNALS
  88.  
  89.     HISTORY
  90.     8-10-95    created by m. fleischer
  91.        16-10-95    increased portability
  92.  
  93. ******************************************************************************/
  94. {
  95.     AROS_LIBFUNC_INIT
  96.     struct Interrupt *lmh;
  97.     struct MemHandlerData lmhd={ byteSize,requirements,0 };
  98.     APTR res = NULL;
  99. #if ENABLE_RT
  100.     ULONG origSize = byteSize;
  101. #endif
  102.  
  103.     D(bug("Call AllocMem (%d, %08lx)\n", byteSize, requirements));
  104.  
  105.     /* Zero bytes requested? May return everything ;-). */
  106.     if(!byteSize)
  107.     goto end;
  108.  
  109.     /* First round byteSize to a multiple of MEMCHUNK_TOTAL. */
  110.     byteSize=(byteSize+MEMCHUNK_TOTAL-1)&~(MEMCHUNK_TOTAL-1);
  111.  
  112.     /* Protect memory list against other tasks */
  113.     Forbid();
  114.  
  115.     /* Loop over low memory handlers */
  116.     lmh=(struct Interrupt *)SysBase->ex_MemHandlers.mlh_Head;
  117.     for(;;)
  118.     {
  119.     struct MemHeader *mh;
  120.     ULONG lmhr;
  121.  
  122.     /* Loop over MemHeader structures */
  123.     mh=(struct MemHeader *)SysBase->MemList.lh_Head;
  124.     while(mh->mh_Node.ln_Succ!=NULL)
  125.     {
  126.         struct MemChunk *p1,*p2;
  127.  
  128.         /*
  129.         Check for the right requirements and enough free memory.
  130.         The requirements are OK if there's no bit in the
  131.         'attributes' that isn't set in the 'mh->mh_Attributes'.
  132.         MEMF_CLEAR, MEMF_REVERSE and MEMF_NO_EXPUNGE are treated
  133.         as if they were always set in the memheader.
  134.         */
  135.         if(!(requirements&~(MEMF_CLEAR|MEMF_REVERSE|
  136.                 MEMF_NO_EXPUNGE|mh->mh_Attributes))
  137.            &&mh->mh_Free>=byteSize)
  138.         {
  139.         struct MemChunk *mc=NULL;
  140.  
  141.         /*
  142.             The free memory list is only single linked, i.e. to remove
  143.             elements from the list I need node's predessor. For the
  144.             first element I can use mh->mh_First instead of a real predessor.
  145.         */
  146.         p1=(struct MemChunk *)&mh->mh_First;
  147.         p2=p1->mc_Next;
  148.  
  149.         /* Is there anything in the list? */
  150.         if(p2!=NULL)
  151.         {
  152.             /* Then follow it */
  153.             for(;;)
  154.             {
  155. #if !defined(NO_CONSISTENCY_CHECKS)
  156.             /* Consistency check: Check alignment restrictions */
  157.             if( ((IPTR)p2|(ULONG)p2->mc_Bytes)
  158.                & (MEMCHUNK_TOTAL-1) )
  159.                 Alert(AN_MemCorrupt|AT_DeadEnd);
  160. #endif
  161.             /* Check if the current block is large enough */
  162.             if(p2->mc_Bytes>=byteSize)
  163.             {
  164.                 /* It is. */
  165.                 mc=p1;
  166.                 /* Use this one if MEMF_REVERSE is not set.*/
  167.                 if(!(requirements&MEMF_REVERSE))
  168.                 break;
  169.                 /* Else continue - there may be more to come. */
  170.             }
  171.  
  172.             /* Go to next block */
  173.             p1=p2;
  174.             p2=p1->mc_Next;
  175.  
  176.             /* Check if this was the end */
  177.             if(p2==NULL)
  178.                 break;
  179. #if !defined(NO_CONSISTENCY_CHECKS)
  180.             /*
  181.                 Consistency check:
  182.                 If the end of the last block+1 is bigger or equal to
  183.                 the start of the current block something must be wrong.
  184.             */
  185.             if((UBYTE *)p2<=(UBYTE *)p1+p1->mc_Bytes)
  186.                 Alert(AN_MemCorrupt|AT_DeadEnd);
  187. #endif
  188.             }
  189.             /* Something found? */
  190.             if(mc!=NULL)
  191.             {
  192.             /*
  193.                 Remember: if MEMF_REVERSE is set
  194.                 p1 and p2 are now invalid.
  195.             */
  196.             p1=mc;
  197.             p2=p1->mc_Next;
  198.  
  199.             /* Remove the block from the list and return it. */
  200.             if(p2->mc_Bytes==byteSize)
  201.             {
  202.                 /* Fits exactly. Just relink the list. */
  203.                 p1->mc_Next=p2->mc_Next;
  204.                 mc=p2;
  205.             }else
  206.             {
  207.                 if(requirements&MEMF_REVERSE)
  208.                 {
  209.                 /* Return the last bytes. */
  210.                 p1->mc_Next=p2;
  211.                 mc=(struct MemChunk *)((UBYTE *)p2+byteSize);
  212.                 }else
  213.                 {
  214.                 /* Return the first bytes. */
  215.                 p1->mc_Next=(struct MemChunk *)((UBYTE *)p2+byteSize);
  216.                 mc=p2;
  217.                 }
  218.                 p1=p1->mc_Next;
  219.                 p1->mc_Next=p2->mc_Next;
  220.                 p1->mc_Bytes=p2->mc_Bytes-byteSize;
  221.             }
  222.             mh->mh_Free-=byteSize;
  223.  
  224.             /* No need to forbid dispatching any longer. */
  225.             Permit();
  226.             if(requirements&MEMF_CLEAR)
  227.             {
  228.                 /* Clear memory. */
  229.                 ULONG cnt,*p;
  230.  
  231.                 p=(ULONG *)mc;
  232.                 cnt=byteSize/sizeof(ULONG);
  233.  
  234.                 while(cnt--)
  235.                 *p++=0;
  236.             }
  237.             res=mc;
  238.             goto end;
  239.             }
  240.         }
  241.         }
  242.         /* Go to next memory header */
  243.         mh=(struct MemHeader *)mh->mh_Node.ln_Succ;
  244.     }
  245.  
  246.     /* Is it forbidden to call low-memory handlers? */
  247.     if(requirements&MEMF_NO_EXPUNGE)
  248.     {
  249.         Permit();
  250.         goto end;
  251.     }
  252.  
  253.     /* All memory headers done. Check low memory handlers. */
  254.     do
  255.     {
  256.         /* Is there another one? */
  257.         if(lmh->is_Node.ln_Succ==NULL)
  258.         {
  259.         /* No. return 'Not enough memory'. */
  260.         Permit();
  261.         goto end;
  262.         }
  263.         /* Yes. Execute it. */
  264.         lmhr = AROS_UFC3 (LONG, lmh->is_Code,
  265.         AROS_UFCA(struct MemHandlerData *,&lmhd,A0),
  266.         AROS_UFCA(APTR,lmh->is_Data,A1),
  267.         AROS_UFCA(struct ExecBase *,SysBase,A6)
  268.         );
  269.  
  270.         /* Check returncode. */
  271.         if(lmhr==MEM_TRY_AGAIN)
  272.         {
  273.         /* MemHandler said he did something. Try again. */
  274.         /* Is there any program that depends on this flag??? */
  275.         lmhd.memh_Flags|=MEMHF_RECYCLE;
  276.         break;
  277.         }
  278.         /* Nothing more to expect from this handler. */
  279.         lmh=(struct Interrupt *)lmh->is_Node.ln_Succ;
  280.         lmhd.memh_Flags&=~MEMHF_RECYCLE;
  281.  
  282.     /*
  283.         If this handler did nothing at all there's no need
  284.         to try the allocation. Try the next handler immediately.
  285.     */
  286.     }while(lmhr==MEM_DID_NOTHING);
  287.     }
  288.  
  289. end:
  290. #if ENABLE_RT
  291.     RT_Add (RTT_MEMORY, res, origSize);
  292. #endif
  293.  
  294.     ReturnPtr ("AllocMem", APTR, res);
  295.     AROS_LIBFUNC_EXIT
  296. } /* AllocMem */
  297.  
  298.